﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace GpuProgramCompiler
{
	internal class ShaderX
	{
		public class CodeBlock
		{
			public String name;
			public String code;
			public List<IOElement> ioElements = new List<IOElement>();
		}

		public class ShaderStage
		{
			public String type;
			public String code;
		}

		public class Shader
		{
			public List<ShaderStage> stages = new List<ShaderStage>();
		}

		public class IOElement
		{
			public String io;
			public String name;
			public String type;
            public String source;
            public String destination;
			public String semantic;
            public int numElements;
			public bool internalConnection = false;
		}

		private List<CodeBlock> codeBlocks = new List<CodeBlock>();
		private List<Shader> shaders = new List<Shader>();

		public List<CodeBlock> CodeBlocks
		{
			get { return codeBlocks; }
		}

		public List<Shader> Shaders
		{
			get { return shaders; }
		}

		public void Load(String filename)
		{
			XmlReader reader = XmlReader.Create(filename);
			if (reader != null)
			{
				while (reader.Read())
				{
					if (reader.NodeType == XmlNodeType.Element)
					{
						if (reader.Name == "Shader")
						{
							ParseShader(reader.ReadSubtree());
							reader.Skip();
						}
						else if (reader.Name == "CodeBlock")
						{
							ParseCodeBlock(reader.ReadSubtree());
							reader.Skip();
						}
					}
				}
				reader.Close();
			}
		}

        public CodeBlock FindCodeBlock(String name)
        {
            foreach (CodeBlock codeBlock in CodeBlocks)
            {
                if (codeBlock.name == name)
                {
                    return codeBlock;
                }
            }

            return null;
        }

		private void ParseShader(XmlReader reader)
		{
			Shader shader = new Shader();
			shaders.Add(shader);

			while (reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element)
				{
					if (reader.Name == "Stage")
					{
						ShaderStage stage = new ShaderStage();
						shader.stages.Add(stage);

						stage.type = reader.GetAttribute("type");
						stage.code = reader.GetAttribute("code");
					}
				}
			}
		}

		private void ParseCodeBlock(XmlReader reader)
		{
			CodeBlock newCodeBlock = new CodeBlock();
			codeBlocks.Add(newCodeBlock);
			
			while (reader.Read())
			{
				if (reader.NodeType == XmlNodeType.Element)
				{
					if (reader.Name == "CodeBlock")
					{
						newCodeBlock.name = reader.GetAttribute("name");
					}
					else if (reader.Name == "Input" || reader.Name == "Output")
					{
						IOElement ioElement = new IOElement();
						ioElement.io = reader.Name.ToLower();
						ioElement.name = reader.GetAttribute("name");
						ioElement.type = reader.GetAttribute("type");
                        ioElement.source = reader.GetAttribute("source");
                        ioElement.destination = reader.GetAttribute("destination");
						ioElement.semantic = reader.GetAttribute("semantic");

                        if (ioElement.source != null)
                            ioElement.source = ioElement.source.ToLower();
                        if (ioElement.destination != null)
                            ioElement.destination = ioElement.destination.ToLower();

                        String numElements = reader.GetAttribute("numElements");
                        ioElement.numElements = 0;
                        if (numElements != null)
                            ioElement.numElements = int.Parse(numElements);

						newCodeBlock.ioElements.Add(ioElement);
					}
					else if (reader.Name == "Code")
					{
						newCodeBlock.code = reader.ReadElementContentAsString().Trim();
					}
				}
			}

		}
	}
}
